#ifndef UnstructMG_PAR_CSRMATRIX_HPP
#define UnstructMG_PAR_CSRMATRIX_HPP

#include "seq_mv.hpp"
#include "par_Vector.hpp"
#include "par_CSRCommPkg.hpp"
#include "_hypre_parcsr_mv.h"
#include "operator.hpp"

template<typename idx_t, typename data_t, typename calc_t, int dof>
class par_CSRMatrix : public Operator<idx_t, calc_t, dof>
{
public:
    MPI_Comm comm = MPI_COMM_NULL;// 通信域
    idx_t glb_nrows;// 矩阵的全局行数
    idx_t beg_row;// 本进程负责的起始行号
    idx_t end_row;// 本进程负责的末尾行号（注意是开区间）
    bool owns_row_partits = false;
    idx_t * rows_partition = nullptr;// 记录各个进程的起始行号

    idx_t glb_ncols;// 矩阵的全局行数
    idx_t beg_col;// 本进程负责的起始行号
    idx_t end_col;// 本进程负责的末尾行号（注意是开区间）
    bool owns_col_partits = false;
    idx_t * cols_partition = nullptr;// 记录各个进程的起始行号

    CSRMatrix<idx_t, data_t, calc_t, dof> diag;// 对角块矩阵
    CSRMatrix<idx_t, data_t, calc_t, dof> offd;// 非对角块矩阵

    bool owns_map_offd = false;
    idx_t * col_map_offd = nullptr;// 将本进程的非对角部分矩阵的局部列序号映射为全局列序号

    bool owns_commpkg = false;
    bool owns_commpkg_transpose = false;
    par_CSRCommPkg<idx_t> * commpkg           = nullptr;
    par_CSRCommPkg<idx_t> * commpkg_transpose = nullptr;

    par_CSRMatrix(MPI_Comm _comm);
    par_CSRMatrix(MPI_Comm _comm,   const idx_t _glb_nrows, const idx_t _beg_row, const idx_t _end_row,
                                    const idx_t _glb_ncols, const idx_t _beg_col, const idx_t _end_col);
    par_CSRMatrix(MPI_Comm _comm, idx_t * _rows_partition, idx_t * _cols_partition);
    ~par_CSRMatrix();

    void set_values_distributed(const int * dist_row_ptr, const idx_t * dist_col_idx,
        const data_t * dist_vals, const bool squeeze_zero = false);
    void set_values_distributed(const long long * dist_row_ptr, const idx_t * dist_col_idx,
        const data_t * dist_vals, const bool squeeze_zero = false);
    void set_values_hypre(const HYPRE_ParCSRMatrix hypre_mat);
    // void set_values_hypre(const void* hypre_ptr);

    // y := alpha*A*x + beta*b
    void Mult(  calc_t alpha, const par_Vector<idx_t, calc_t, dof> & x,
                calc_t beta , const par_Vector<idx_t, calc_t, dof> & b, par_Vector<idx_t, calc_t, dof> & y) const;

    void Mult(const par_Vector<idx_t, calc_t, dof> & x, 
                    par_Vector<idx_t, calc_t, dof> & y, bool use_zero_guess) const;
    void truncate();

    void calc_ranges();

    void prepare_commpkg(std::unordered_map<idx_t, std::pair<int, idx_t> > & glb2pidloc);
    // void transpose_commpkg();

    // 幂迭代计算最大特征值
    calc_t power_iteration(idx_t max_iter, const Operator<idx_t, calc_t, dof> * prec = nullptr) const;

};
typedef par_CSRMatrix<int, float , float , 1> par_CSRMatrix_I32F32F32_DOF1;
typedef par_CSRMatrix<int, float , float , 2> par_CSRMatrix_I32F32F32_DOF2;
typedef par_CSRMatrix<int, float , float , 3> par_CSRMatrix_I32F32F32_DOF3;
typedef par_CSRMatrix<int, float , float , 4> par_CSRMatrix_I32F32F32_DOF4;

typedef par_CSRMatrix<int, float , double, 1> par_CSRMatrix_I32F32F64_DOF1;
typedef par_CSRMatrix<int, float , double, 2> par_CSRMatrix_I32F32F64_DOF2;
typedef par_CSRMatrix<int, float , double, 3> par_CSRMatrix_I32F32F64_DOF3;
typedef par_CSRMatrix<int, float , double, 4> par_CSRMatrix_I32F32F64_DOF4;

typedef par_CSRMatrix<int, double, double, 1> par_CSRMatrix_I32F64F64_DOF1;
typedef par_CSRMatrix<int, double, double, 2> par_CSRMatrix_I32F64F64_DOF2;
typedef par_CSRMatrix<int, double, double, 3> par_CSRMatrix_I32F64F64_DOF3;
typedef par_CSRMatrix<int, double, double, 4> par_CSRMatrix_I32F64F64_DOF4;
#ifdef USE_FP16
typedef par_CSRMatrix<int, __fp16, float , 1> par_CSRMatrix_I32F16F32_DOF1;
typedef par_CSRMatrix<int, __fp16, float , 2> par_CSRMatrix_I32F16F32_DOF2;
typedef par_CSRMatrix<int, __fp16, float , 3> par_CSRMatrix_I32F16F32_DOF3;
typedef par_CSRMatrix<int, __fp16, float , 4> par_CSRMatrix_I32F16F32_DOF4;

typedef par_CSRMatrix<int, __fp16, double, 1> par_CSRMatrix_I32F16F64_DOF1;
typedef par_CSRMatrix<int, __fp16, double, 2> par_CSRMatrix_I32F16F64_DOF2;
typedef par_CSRMatrix<int, __fp16, double, 3> par_CSRMatrix_I32F16F64_DOF3;
typedef par_CSRMatrix<int, __fp16, double, 4> par_CSRMatrix_I32F16F64_DOF4;
#endif

// typedef par_CSRMatrix<int, long long, float , float , 1> par_CSRMatrix_I64F32F32_DOF1;
// typedef par_CSRMatrix<int, long long, float , float , 2> par_CSRMatrix_I64F32F32_DOF2;
// typedef par_CSRMatrix<int, long long, float , float , 3> par_CSRMatrix_I64F32F32_DOF3;
// typedef par_CSRMatrix<int, long long, float , float , 4> par_CSRMatrix_I64F32F32_DOF4;

// typedef par_CSRMatrix<int, long long, float , double, 1> par_CSRMatrix_I64F32F64_DOF1;
// typedef par_CSRMatrix<int, long long, float , double, 2> par_CSRMatrix_I64F32F64_DOF2;
// typedef par_CSRMatrix<int, long long, float , double, 3> par_CSRMatrix_I64F32F64_DOF3;
// typedef par_CSRMatrix<int, long long, float , double, 4> par_CSRMatrix_I64F32F64_DOF4;

// typedef par_CSRMatrix<int, long long, double, double, 1> par_CSRMatrix_I64F64F64_DOF1;
// typedef par_CSRMatrix<int, long long, double, double, 2> par_CSRMatrix_I64F64F64_DOF2;
// typedef par_CSRMatrix<int, long long, double, double, 3> par_CSRMatrix_I64F64F64_DOF3;
// typedef par_CSRMatrix<int, long long, double, double, 4> par_CSRMatrix_I64F64F64_DOF4;
// #ifdef USE_FP16
// typedef par_CSRMatrix<int, long long, __fp16, float , 1> par_CSRMatrix_I64F16F32_DOF1;
// typedef par_CSRMatrix<int, long long, __fp16, float , 2> par_CSRMatrix_I64F16F32_DOF2;
// typedef par_CSRMatrix<int, long long, __fp16, float , 3> par_CSRMatrix_I64F16F32_DOF3;
// typedef par_CSRMatrix<int, long long, __fp16, float , 4> par_CSRMatrix_I64F16F32_DOF4;

// typedef par_CSRMatrix<int, long long, __fp16, double, 1> par_CSRMatrix_I64F16F64_DOF1;
// typedef par_CSRMatrix<int, long long, __fp16, double, 2> par_CSRMatrix_I64F16F64_DOF2;
// typedef par_CSRMatrix<int, long long, __fp16, double, 3> par_CSRMatrix_I64F16F64_DOF3;
// typedef par_CSRMatrix<int, long long, __fp16, double, 4> par_CSRMatrix_I64F16F64_DOF4;
// #endif



#endif